#include <string.h>

#include "els.h"
#include "els_heap.h"
#include "els_func.h"
#include "els_gc.h"
#include "els_mem.h"
#include "els_object.h"
#include "els_vmhost.h"
#include "els_string.h"
#include "els_unit.h"
#include "els_vmcore.h"

#define GCscale(x)		((int)((x)>>10))
#define GCunscale(x)		((unsigned long)(x)<<10)
#define Index(L,i)	((i) >= 0 ? (L->Cbase+((i)-1)) : (L->top+(i)))
#define api_incr_top(L)	incr_top
#define els_API_index(l,index) Index(l, index)

extern void els_API_pushobject (els_VmObj *L, const StackObj *o);
extern int parse_file(els_VmObj *L, const char *filename);
extern int parse_buffer(els_VmObj *L, const char *buff, size_t size,const char *name);


StackObj *els_getstackobj (els_VmObj *L, int index) {
  if (index >= 0) {
    StackObj *o = L->Cbase+(index-1);
    if (o >= L->top)  o->ttype=ELS_TYPE_NULL;
    return o;
  }
  else return L->top+index;
}

void els_API_pushobject (els_VmObj *L, const StackObj *o) {
  *L->top = *o;
  incr_top;
}

/*VM api*/
ELS_API els_VmObj *els_createvm (int stacksize);
ELS_API void els_closevm (els_VmObj *L) ;

ELS_API void els_error(els_VmObj *L, const char *s)
{
  printf("EasyLosu Script Error: \t%s\n",s);
  els_Heap_breakrun(L, ELS_ERRRUN);
}


/*exec api*/
ELS_API int els_call (els_VmObj *L, int nargs, int nresults) ;

ELS_API int els_dostring(els_VmObj *L, const char *str) {
    int i;
    if (!(i=parse_buffer(L, str, strlen(str), str)))
      return els_call(L, 0, ELS_MULTRET);
    return i;
}

ELS_API int els_dofile(els_VmObj *L, const char *filename)
{
    int i;
    if (! ( i = parse_file(L, filename)) )
        return els_call(L, 0, ELS_MULTRET);    
    return i;
}


/*api type is*/
ELS_API int els_type (els_VmObj *L, int index) {
  return ttype(els_getstackobj(L, index));
}


/*api stack get*/
ELS_API double els_getnum (els_VmObj *L, int index) {
  Els_vminline_obj o = els_getstackobj(L, index);
  return (o == NULL || tonumber(o)) ? 0 : nvalue(o);
}

ELS_API const char *els_getstr (els_VmObj *L, int index) {
  Els_vminline_obj o = els_getstackobj(L, index);
  return (o == NULL || tostring(L, o)) ? "" : svalue(o);
}

ELS_API els_CFunction els_getfunc (els_VmObj *L, int index) {
  Els_vminline_obj o = els_getstackobj(L, index);
  return (o == NULL || !iscfunction(o)) ? NULL : clvalue(o)->f.c;
}

ELS_API void els_getvmvalue (els_VmObj *L, const char *name) {
  Els_vminline_obj top = L->top;
  *top = *els_Vmcore_getglobal(L, els_string_new(L, name));
  L->top = top;
  api_incr_top(L);
}



ELS_API void els_pushnull (els_VmObj *L) {
  ttype(L->top) = ELS_TYPE_NULL;
  api_incr_top(L);
}

ELS_API void els_pushnum (els_VmObj *L, double n) {
  nvalue(L->top) = n;
  ttype(L->top) = ELS_TYPE_NUMBER;
  api_incr_top(L);
}

ELS_API void els_pushstr (els_VmObj *L, const char *s) {
  if (s == NULL)
    els_pushnull(L);
  else{
    tsvalue(L->top) = els_string_newlstr(L, s, strlen(s));
    ttype(L->top) = ELS_TYPE_STRING;
    api_incr_top(L);
  }
}

ELS_API void els_pushvmvalue (els_VmObj *L, const char *name) {
  Els_vminline_obj top = L->top;
  els_Vmcore_setglobal(L, els_string_new(L, name));
  L->top = top-1;  /* remove element from the top */
}


ELS_API void els_pushcfunciotn (els_VmObj *L, els_CFunction fn, int n) {
  els_Vmcore_C_csfunciotn(L, fn, n);
}

ELS_API void els_settop(els_VmObj *L,int index)
{
  if (index >= 0)
    els_Heap_adjusttop(L, L->Cbase, index);
  else
    L->top = L->top+index+1;  
}


